// 利用图可视化引擎-G6（https://g6.antv.antgroup.com/manual/introduction），开发网络拓扑
<template>
  <div class="g6-wrap h-100">
    <div :id="id" :ref="id" class="h-100" />
  </div>
</template>
<script>
  import { mapGetters } from 'vuex'
  import G6 from '@antv/g6'
  import config from './js/config'
  import { deepClone } from '@/utils/common'
  import getThemeColor from '@/utils/themesColor'
  export default {
    props: {
      id: {
        type: String,
        default: 'g6-container'
      },
      nodes: {
        type: Array,
        default: () => []
      },
      edges: {
        type: Array,
        default: () => []
      },
      isEdit: {
        type: Boolean,
        default: false
      }
    },
    data() {
      return {
        G6: null,
        graph: null,
        graphOffsetTop: 0,
        mouseEvent: '',
        cloneNodes: []
      }
    },
    computed: {
      ...mapGetters(['baseRegionList'])
    },
    watch: {
      nodes: {
        handler(newVal, oldVal) {
          console.log('点击了刷新', newVal)
          this.cloneNodes = deepClone(this.nodes)
          this.init()
        }
      }
    },
    mounted() {
      this.$nextTick(() => {
        this.cloneNodes = deepClone(this.nodes)
        this.init()
      })
    },
    beforeDestroy() {
      this.destroy()
    },
    methods: {
      init() {
        this.destroy()
        const g6Container = document.getElementById(this.id)
        if (!g6Container) return
        this.graph = new G6.Graph({
          ...config,
          container: g6Container,
          width: g6Container.scrollWidth,
          height: g6Container.scrollHeight,
          showMiniMap: false
        })
        this.renderTopo()
        this.addEvent()
      },
      renderTopo() {
        const nodes = []
        let roomIds = []
        this.cloneNodes.forEach(i => {
          const data = {
            type: 'circle',
            id: i.id.toString(),
            label: i.label,
            style: {
              fill: 'transparent',
              stroke: 'transparent'
            },
            labelCfg: {
              style: {
                fill: i.font.color
              }
            },
            icon: {
              show: true,
              opacity: 1,
              fontFamily: 'iconfont',
              fill: i.icon.color,
              text: i.icon.code,
              fontSize: i.icon.size,
              cursor: 'pointer'
            },
            x: i.x,
            y: i.y,
            info: i
          }
          if (i.roomId) {
            data.comboId = i.roomId
            roomIds.push(i.roomId)
          }
          i.roomId && roomIds.push(i.roomId)
          nodes.push(data)
        })
        const edges = []
        this.edges.forEach(i => {
          edges.push({
            id: i.id,
            label: i.label,
            source: i.from.toString(),
            target: i.to.toString(),
            style: {
              stroke: i.color.color,
              strokeOpacity: i.color.opacity || 0.5,
              lineWidth: 2
            },
            labelCfg: {
              style: {
                fill: i.font.color
              }
            },
            info: i
          })
        })
        G6.Util.processParallelEdges(edges, 15, 'quadratic', 'line') // 2个节点间存在多条边时，设置边不重叠
        // 处理分组
        roomIds = Array.from(new Set(roomIds))
        const combos = []
        roomIds.forEach(i => {
          const data = {
            id: i,
            label: this.getRoomName(i),
            style: {
              fill: getThemeColor('topoColor'),
              stroke: getThemeColor('bgColor'),
              opacity: 0.2
            }
          }
          combos.push(data)
        })
        this.graph.changeData({
          nodes: nodes,
          edges: edges,
          combos: combos
        })
        this.graph.fitView()
      },
      addEvent() {
        const mainBox = document.querySelector('#mapContainer').getBoundingClientRect()
        const left = mainBox.left - 15
        const top = mainBox.top - 15
        this.graph.on('node:click', evt => {
          // console.log('选中节点', evt)
          const nodeItem = evt.item
          // this.graph.clearItemStates(nodeItem)
          nodeItem.clearStates()
          const model = nodeItem.getModel()
          if (this.isEdit) return
          this.mouseEvent = 'stationClick'
          this.$emit('selectNode', {
            ...model.info,
            mouseEvent: 'stationClick',
            ...{
              id: model.id,
              mouseStatus: 'SELECT',
              left: evt.clientX - left,
              top: evt.clientY - top
            }
          })
        })
        this.graph.on('node:mouseenter', evt => {
          console.log('节点移入', evt)
          if (this.isEdit) return
          const nodeItem = evt.item
          const model = nodeItem.getModel()
          if (this.curNode && model.info.id !== this.curNode.info.id) {
            this.mouseEvent = 'stationHover'
          }
          this.curNode = model
          if (this.mouseEvent !== 'stationClick') {
            this.$emit('hoverNode', {
              ...model.info,
              mouseStatus: 'HOVER',
              mouseEvent: 'stationHover',
              left: evt.clientX - left,
              top: evt.clientY - top
            })
          }
        })
        this.graph.on('node:mouseleave', evt => {
          console.log('节点移出', evt)
          if (this.isEdit) return
          const nodeItem = evt.item
          const model = nodeItem.getModel()
          if (this.mouseEvent !== 'stationClick') {
            this.$emit('hoverNode', {
              ...model.info,
              mouseStatus: 'LEAVE',
              mouseEvent: '',
              left: 0,
              top: 0
            })
          }
        })
        this.graph.on('edge:click', evt => {
          this.$emit('selectNode', {
            mouseStatus: '',
            left: 0,
            top: 0
          })
          if (this.isEdit) return
          const edgeItem = evt.item
          const model = edgeItem.getModel()
          this.$emit('selectEdge', {
            ...model.info,
            mouseStatus: 'SELECT'
          })
        })
        this.graph.on('edge:mouseenter', evt => {
          // console.log('边移入', evt)
          this.$emit('selectNode', {
            mouseStatus: '',
            left: 0,
            top: 0
          })
          if (this.isEdit) return
          const edgeItem = evt.item
          edgeItem.update({ style: {
            lineWidth: 4
          }})
          this.$emit('hoverEdge', {
            ...edgeItem.getModel().info,
            mouseStatus: 'HOVER',
            left: evt.clientX - left,
            top: evt.clientY - top
          })
        })
        this.graph.on('edge:mouseleave', evt => {
          // console.log('边移出', evt)
          if (this.isEdit) return
          const edgeItem = evt.item
          edgeItem.update({ style: {
            lineWidth: 2
          }})
          this.$emit('hoverEdge', {
            mouseStatus: 'LEAVE',
            left: 0,
            top: 0
          })
        })
        this.graph.on('canvas:click', evt => {
          this.clearState()
        })
        this.graph.on('canvas:dragstart', evt => {
          this.clearState()
        })
      },
      setEditable(val) {
        this.graph && this.graph.setMode(val ? 'edit' : 'default')
      },
      fitView(width, height) {
        const g6WrapWH = document.querySelector('.g6-wrap').getBoundingClientRect()
        console.log(g6WrapWH)
        const w = Math.floor(width || g6WrapWH.width)
        const h = Math.floor(height || g6WrapWH.height)
        if (this.graph) {
          this.graph.changeSize(w, h)
          this.graph.fitView()
        }
      },
      clearState() {
        this.$emit('selectNode', {
          mouseStatus: '',
          left: 0,
          top: 0
        })
      },
      destroy() {
        if (this.graph) {
          this.graph.clear() // 清空画布内容
          this.graph.destroy() // 销毁画布
          this.graph.off() // 解除所有元素的监听事件
          this.graph = null
        }
      },
      // 获取机房
      getRoomName(stationId) {
        const stationData = this.baseRegionList.find(i => i.regionId === stationId)
        return stationData ? stationData.regionName : ''
      }
    }
  }
</script>
